package javase_class_250911;

/**
 * ClassName: TicketSafe1
 * Package: javase_class_250911
 * Description:
 *
 * @Author harkjeans
 * @Create 2025/9/11 15:05
 * @Version 1.0
 */
//方案一：同步方法（Synchronized Method）
public class TicketSafe1 implements Runnable{
    private int ticketCount = 10;

    @Override
    public void run() {
        while (true) {
            if (sellTicket() <= 0) { // 调用同步卖票方法
                break; // 如果返回的票数<=0，就结束循环
            }
        }
    }

    // 添加 synchronized 关键字，使方法成为同步方法
//    private synchronized int sellTicket() {
//        if (ticketCount > 0) {
//            try {
//                Thread.sleep(100);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(Thread.currentThread().getName() + " 卖出一张票，剩余: " + (--ticketCount));
//        }
//        return ticketCount; // 返回当前剩余票数
//    }
    private synchronized int sellTicket() {
        System.out.println(Thread.currentThread().getName() + " 获得了锁，开始卖票");
        if (ticketCount > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " 卖出一张票，剩余: " + (--ticketCount));
        }
        System.out.println(Thread.currentThread().getName() + " 释放了锁");
        return ticketCount;
    }
    // ... main方法同上
    public static void main(String[] args) {
        TicketSafe1 ticket = new TicketSafe1(); // 创建一个票源
        // 创建三个线程（窗口），共享同一个票源
        Thread window1 = new Thread(ticket, "窗口1");
        Thread window2 = new Thread(ticket, "窗口2");
        Thread window3 = new Thread(ticket, "窗口3");

        // 同时开始卖票
        window1.start();
        window2.start();
        window3.start();
    }
}
/**
 * 原理：
 *
 * synchronized 方法默认使用当前对象（this） 作为锁。
 *
 * 一个线程（如窗口1）进入 sellTicket() 方法前会先获取 this 锁。
 *
 * 在此期间，其他线程（窗口2、3）也想进入该方法时，会发现锁已被占用，于是进入阻塞状态（BLOCKED），乖乖排队等待。
 *
 * 直到窗口1执行完方法释放锁，等待的线程中的一个才能抢到锁进入方法。
 *
 * 这样就确保了 --ticketCount 这个关键操作时刻只有一个线程在执行。
 *
 *
 */
